package com.gd.iot.energy.service.superadmin.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.gd.iot.energy.code.ResponseCode;
import com.gd.iot.energy.consts.SystemConsts;
import com.gd.iot.energy.dao.superadmin.PermissionPOMapper;
import com.gd.iot.energy.dao.superadmin.RolePermissionPOMapper;
import com.gd.iot.energy.exception.MyException;
import com.gd.iot.energy.po.superadmin.AdminPO;
import com.gd.iot.energy.po.superadmin.PermissionPO;
import com.gd.iot.energy.po.superadmin.RolePermissionPO;
import com.gd.iot.energy.pojo.common.vo.ColumnVO;
import com.gd.iot.energy.pojo.common.vo.PageVO;
import com.gd.iot.energy.pojo.superadmin.dto.PermissionSaveDTO;
import com.gd.iot.energy.pojo.superadmin.vo.PermissionVO;
import com.gd.iot.energy.service.superadmin.PermissionService;
import com.gd.iot.energy.util.CurrentUserUtil;
import com.gd.iot.energy.util.CustomBeanUtils;
import com.gd.iot.energy.util.CustomColumnUtil;
import com.gd.iot.energy.util.EnergyTypeUtil;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 权限service
 *
 * @author kris
 * @date Created at 8:33 下午 2020/8/5
 */
@Service
public class PermissionServiceImpl implements PermissionService {

    @Resource
    private PermissionPOMapper permissionPOMapper;

    @Resource
    private RolePermissionPOMapper rolePermissionPOMapper;

    private static final Integer DEFAULT_ORDER_NUM = 999;

    /**
     * 表头配置文件
     */
    private static final String PERMISSION_LIST_COLUMN_FILE_NAME = "superadmin/permission_list.column";

    @Override
    public PageVO<PermissionVO> getPermissionVOs() {
        QueryWrapper<PermissionPO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("is_del", SystemConsts.BooleanEnum.FALSE.value);
        EnergyTypeUtil.injectEnergyTypeWrapper(queryWrapper);
        queryWrapper.orderByAsc("order_num");
        List<PermissionPO> permissionPOS = permissionPOMapper.selectList(queryWrapper);
        List<PermissionVO> permissionVOList = convertToPermissionVOList(permissionPOS);
        PageVO<PermissionVO> pageVO = new PageVO<>();
        pageVO.setData(permissionVOList);
        List<ColumnVO> columns = CustomColumnUtil.getColumn(PERMISSION_LIST_COLUMN_FILE_NAME);
        pageVO.setColumns(columns);
        return pageVO;
    }

    /**
     * dto 转VO
     *
     * @param permissionPOS
     * @return
     */
    private List<PermissionVO> convertToPermissionVOList(List<PermissionPO> permissionPOS) {
        List<PermissionVO> res = new ArrayList<>(permissionPOS.size());
        PermissionVO permissionVO;
        int i = 1;
        for (PermissionPO permissionPO : permissionPOS) {
            permissionVO = new PermissionVO();
            permissionVO.setCreateDate(DateUtil.formatDate(permissionPO.getCreateDate()));
            permissionVO.setId(permissionPO.getId());
            permissionVO.setName(permissionPO.getName());
            permissionVO.setDescription(permissionPO.getDescription());
            permissionVO.setDepth(permissionPO.getDepth());
            permissionVO.setOrderNum(permissionPO.getOrderNum());
            permissionVO.setPerms(permissionPO.getPerms());
            permissionVO.setType(SystemConsts.PermissionEnum.getNameByValue(permissionPO.getType()));
            permissionVO.setParentId(permissionPO.getParentId());
            permissionVO.setSerialNum(i);
            res.add(permissionVO);
            i++;
        }
        return res;
    }

    @Override
    public boolean savePermissions(List<Integer> permissionIds, Integer roleId) {
        if (CollUtil.isEmpty(permissionIds) || roleId == null) {
            return true;
        }

        //删除老数据
        QueryWrapper<RolePermissionPO> queryWrapper = new QueryWrapper<>();
        EnergyTypeUtil.injectEnergyTypeWrapper(queryWrapper);
        queryWrapper.eq("role_id", roleId);
        rolePermissionPOMapper.delete(queryWrapper);

        RolePermissionPO rolePermissionPO;
        for (Integer permissionId : permissionIds) {
            if (permissionId == null) {
                continue;
            }
            rolePermissionPO = new RolePermissionPO();
            rolePermissionPO.setPermissionId(permissionId);
            rolePermissionPO.setRoleId(roleId);
            rolePermissionPO.setEnergyType(SystemConsts.EnergyTypeEnum.WATER.value);
            rolePermissionPOMapper.insert(rolePermissionPO);
        }
        return true;
    }

    @Override
    public List<Integer> getPermissionsByRoleId(Integer roleId) {
        QueryWrapper<RolePermissionPO> queryWrapper = new QueryWrapper<>();
        EnergyTypeUtil.injectEnergyTypeWrapper(queryWrapper);
        queryWrapper.eq("role_id", roleId);
        List<RolePermissionPO> rolePermissionPOS = rolePermissionPOMapper.selectList(queryWrapper);
        return rolePermissionPOS.stream()
                .map(RolePermissionPO::getPermissionId)
                .collect(Collectors.toList());
    }

    @Override
    public Integer add(PermissionSaveDTO permissionSaveDTO) {
        if (StrUtil.isBlank(permissionSaveDTO.getName())
                || permissionSaveDTO.getType() == null
                || StrUtil.isBlank(permissionSaveDTO.getPerms())) {
            throw new MyException(ResponseCode.PARAMETER_REQUIRED);
        }
        PermissionPO permissionPO = new PermissionPO();
        permissionPO.setCreateDate(new Date());
        permissionPO.setEnergyType(SystemConsts.EnergyTypeEnum.WATER.value);
        permissionPO.setIsDel(SystemConsts.BooleanEnum.FALSE.value);
        permissionPO.setName(permissionSaveDTO.getName());
        permissionPO.setDescription(permissionSaveDTO.getDescription());
        permissionPO.setOrderNum(permissionSaveDTO.getOrderNum() == null ? DEFAULT_ORDER_NUM : permissionSaveDTO.getOrderNum());
        permissionPO.setParentId(permissionSaveDTO.getParentId() == null ? 0 : permissionSaveDTO.getParentId());
        permissionPO.setPerms(permissionSaveDTO.getPerms().trim());
        permissionPO.setType(permissionSaveDTO.getType());

        PermissionPO parentPermission = getParentPermission(permissionPO.getParentId());
        validateType(permissionSaveDTO.getType(), parentPermission);
        Integer depth = getDepthByParent(parentPermission);
        permissionPO.setDepth(depth);
        permissionPOMapper.insert(permissionPO);
        return permissionPO.getId();
    }

    /**
     * 校验类型
     *
     * @param type
     * @param parentPermission
     */
    private void validateType(Integer type, PermissionPO parentPermission) {

        //子层级的类型不能小于父层级的类型
        if (parentPermission.getType() > type) {
            throw new MyException(ResponseCode.PERMISSION_TYPE_ERROR);
        }
        //类型是否合法
        for (SystemConsts.PermissionEnum value : SystemConsts.PermissionEnum.values()) {
            if (value.value.equals(type)) {
                return;
            }
        }
        throw new MyException(ResponseCode.PARAMETER_ERROR);
    }

    /**
     * 父级
     *
     * @param parentId
     * @return
     */
    private PermissionPO getParentPermission(Integer parentId) {
        PermissionPO permissionParent = null;
        if (parentId != null && parentId != 0) {
            permissionParent = permissionPOMapper.selectById(parentId);
            if (permissionParent == null || permissionParent.getIsDel().equals(SystemConsts.BooleanEnum.TRUE.value)) {
                throw new MyException(ResponseCode.PARENT_NOT_EXIST);
            }
        }
        return permissionParent;
    }

    /**
     * 通过父分类查询层级
     *
     * @param permissionPO
     * @return
     */
    private Integer getDepthByParent(PermissionPO permissionPO) {
        int depth = 0;
        if (permissionPO != null) {
            depth = permissionPO.getDepth() + 1;
        }
        return depth;
    }

    @Override
    public boolean updatePermission(PermissionSaveDTO permissionSaveDTO) {
        if (StrUtil.isBlank(permissionSaveDTO.getName())
                || permissionSaveDTO.getType() == null
                || StrUtil.isBlank(permissionSaveDTO.getPerms())) {
            throw new MyException(ResponseCode.PARAMETER_REQUIRED);
        }
        PermissionPO permissionPO = new PermissionPO();
        permissionPO.setId(permissionSaveDTO.getId());
        permissionPO.setModifyDate(new Date());
        permissionPO.setName(permissionSaveDTO.getName());
        permissionPO.setDescription(permissionSaveDTO.getDescription());
        permissionPO.setOrderNum(permissionSaveDTO.getOrderNum() == null ? DEFAULT_ORDER_NUM : permissionSaveDTO.getOrderNum());
        permissionPO.setPerms(permissionSaveDTO.getPerms().trim());
        int num = permissionPOMapper.updateById(permissionPO);
        return num > 0;
    }

    @Override
    public boolean delete(List<Integer> ids) {
        if(CollUtil.isEmpty(ids)){
            throw new MyException(ResponseCode.PARAMETER_REQUIRED);
        }

        //校验删除的权限下面是否存在子级
        hasChildren(ids);

        //管理员表逻辑删除
        QueryWrapper<PermissionPO> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("id", ids);
        EnergyTypeUtil.injectEnergyTypeWrapper(queryWrapper);
        PermissionPO permissionPO = new PermissionPO();
        permissionPO.setIsDel(SystemConsts.BooleanEnum.TRUE.value);
        int num = permissionPOMapper.update(permissionPO,queryWrapper);

        return num > 0;
    }

    @Override
    public List<PermissionVO> getCurrentUserPermissionVOs() {

        List<PermissionPO> userPermissions = permissionPOMapper.getPermissionsByAdminId(CurrentUserUtil.getUserInfo().getId(),
                SystemConsts.EnergyTypeEnum.WATER.value);

        List<Integer> userPermissionIds = userPermissions.stream()
                .map(PermissionPO::getId).collect(Collectors.toList());

        QueryWrapper<PermissionPO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("is_del", SystemConsts.BooleanEnum.FALSE.value);
        EnergyTypeUtil.injectEnergyTypeWrapper(queryWrapper);

        List<PermissionPO> allPermissionPOS = permissionPOMapper.selectList(queryWrapper);

        Map<Integer, PermissionPO> idPermissionPOMap = allPermissionPOS.stream()
                .collect(Collectors.toMap(PermissionPO::getId,v->v));

        Set<PermissionPO> userAllPermission = new HashSet<>();

        for (Integer userPermissionId : userPermissionIds) {
            PermissionPO permissionPO = idPermissionPOMap.get(userPermissionId);
            addParentPermission(permissionPO,idPermissionPOMap,userAllPermission);
        }
        List<PermissionVO> res = new ArrayList<>();
        CustomBeanUtils.convertPojo(userAllPermission,res,PermissionVO.class);
        return res;
    }

    /**
     * 地柜获取父级id
     * @param permissionPO
     * @param idPermissionPOMap
     * @param userAllPermission
     */
    private void addParentPermission(PermissionPO permissionPO, Map<Integer, PermissionPO> idPermissionPOMap, Set<PermissionPO> userAllPermission) {
        userAllPermission.add(permissionPO);
        if(permissionPO!=null && permissionPO.getParentId()!=0){
            PermissionPO parentPermissionPO = idPermissionPOMap.get(permissionPO.getParentId());
            addParentPermission(parentPermissionPO,idPermissionPOMap,userAllPermission);
        }
    }

    /**
     * 校验删除的权限下面是否存在子级
     * @param ids
     */
    private void hasChildren(List<Integer> ids) {
        QueryWrapper<PermissionPO> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("parent_id", ids);
        queryWrapper.eq("is_del", SystemConsts.BooleanEnum.FALSE.value);
        EnergyTypeUtil.injectEnergyTypeWrapper(queryWrapper);
        if (permissionPOMapper.selectCount(queryWrapper)>0){
            throw new MyException(ResponseCode.HAS_CHILD);
        }
    }
}
